import os, json
import mysql.connector
import oracledb
from typing import List, Dict, Any, Tuple, Union
from tqdm import tqdm
from convert import *
from mock import *


def read_json(
    abs_path: str = os.getcwd(),
) -> List[Tuple[str, Dict[str, Any]]]:
    """
    从给定路径中尝试读取json文件存储为dict集合并返回。

    参数
    - abs_path: 绝对路径，默认当前路径。
      1. 可直接传入文件路径，读取文件内容转化为dict。
      2. 非文件路径，尝试读取路径下的所有json文件，并逐一解析json内容转化为dict。
      3. 创建结果tuple，索引0存储文件名，索引1存储dict。

    返回
    返回结果tuple或包含多个结果的list。[("test",{"test":"测试", "value": "test_data"})]
    """
    results = []

    # 检查路径是否为文件
    if os.path.isfile(abs_path):
        # 读取单个 JSON 文件
        with open(abs_path, "r", encoding="utf-8") as file:
            try:
                data = json.load(file)
                results.append(
                    (os.path.splitext(os.path.basename(abs_path))[0], data)
                )  # 返回单个元组
            except json.JSONDecodeError:
                print(f"文件 {abs_path} 不是有效的 JSON 格式。")
    elif os.path.isdir(abs_path):
        # 读取目录下的所有 JSON 文件
        for filename in os.listdir(abs_path):
            if filename.endswith(".json"):
                file_path = os.path.join(abs_path, filename)
                with open(file_path, "r", encoding="utf-8") as file:
                    try:
                        data = json.load(file)
                        results.append(
                            (os.path.splitext(filename)[0], data)
                        )  # 添加元组到结果列表
                    except json.JSONDecodeError:
                        print(f"文件 {file_path} 不是有效的 JSON 格式，跳过。")

    else:
        print(f"路径 {abs_path} 不存在或不是文件/目录。")

    return results  # 返回包含多个元组的列表


def read_sql(
    abs_path: str = os.getcwd(),
) -> List[str]:
    """
    从给定路径中尝试读取 SQL 文件并提取所有 SQL 语句。

    参数
    - abs_path: 绝对路径，默认当前路径。
      1. 可直接传入文件路径，读取文件内容并提取 SQL 语句。
      2. 非文件路径，尝试读取路径下的所有 SQL 文件，并逐一解析内容。

    返回
    返回包含所有 SQL 语句的列表。例如：["SELECT * FROM test;", "INSERT INTO test VALUES (1, 'data');"]
    """
    sql_statements = []

    # 检查路径是否为文件
    if os.path.isfile(abs_path):
        # 读取单个 SQL 文件
        with open(abs_path, "r", encoding="utf-8") as file:
            content = file.read()
            sql_statements.extend(parse_sql(content))  # 解析 SQL 并添加到列表

    elif os.path.isdir(abs_path):
        # 读取目录下的所有 SQL 文件
        for filename in os.listdir(abs_path):
            if filename.endswith(".sql"):
                file_path = os.path.join(abs_path, filename)
                with open(file_path, "r", encoding="utf-8") as file:
                    content = file.read()
                    sql_statements.extend(parse_sql(content))  # 解析 SQL 并添加到列表

    else:
        print(f"路径 {abs_path} 不存在或不是文件/目录。")

    return sql_statements  # 返回包含所有 SQL 语句的列表


def parse_sql(content: str) -> List[str]:
    """
    从给定的 SQL 内容中提取出 SQL 语句。

    参数
    - content: 包含 SQL 语句的字符串。

    返回
    返回提取出的 SQL 语句列表。
    """
    # 根据分号分割 SQL 语句，并去除空白
    statements = [stmt.strip() for stmt in content.split(";") if stmt.strip()]
    return statements


def config_analysis(args_dict: Dict[str, Any]) -> List[tuple[str, Union[str, bytes]]]:
    # 获取配置路径
    mock_list = []
    try:
        source_path = args_dict["source"]
        config_list = read_json(source_path)
        for config_template in config_list:
            mock_list.extend(mock_data(config_template, args_dict))
    except Exception as e:
        print("模板配置有问题，请检查", e)

    return convert([data for data in mock_list])


def parse_db_info(db_info: str) -> Dict[str, Any]:
    """解析数据库连接信息字符串。"""
    if "@" not in db_info:
        print("数据库信息格式无效")
        return {}

    user_password, host_port_service = db_info.split("@")
    user, password = user_password.split(":")

    if ":" not in host_port_service:
        print("主机：端口/service_name格式无效")
        return {}

    host_port, database = host_port_service.split("/")
    host, port = host_port.split(":")

    return {
        "user": user,
        "password": password,
        "host": host,
        "port": int(port),
        "database": database,
    }


def execute_dml(args_dict: Dict[str, Any], source_path: str):
    dbType = args_dict["dbType"]
    if dbType not in ("mysql", "oracle"):
        dbType = "mysql"

    dbInfo = args_dict["dbInfo"]
    db_params = parse_db_info(dbInfo)

    connection = None
    cursor = None
    progress_bar = None

    sql_list = read_sql(source_path)
    if not sql_list:
        print("未解析出有效SQL语句，跳过执行")
        return

    try:
        if dbType == "mysql":
            # 获取 MySQL 连接参数
            user = db_params["user"]
            password = db_params["password"]
            host = db_params["host"]
            port = db_params["port"]
            database = db_params["database"]

            # 连接到 MySQL 数据库
            connection = mysql.connector.connect(
                host=host, port=port, user=user, password=password, database=database
            )
            cursor = connection.cursor()
            print("成功连接到MYSQL数据库")
            print(
                f"用户名: {user} 密码：{password} 主机：{host} 端口：{port} 数据库: {database}"
            )

        elif dbType == "oracle":
            # 获取 Oracle 连接参数
            user = db_params["user"]
            password = db_params["password"]
            host = db_params["host"]
            port = db_params["port"]
            service_name = db_params["database"]
            lib_dir = r"instantclient"

            # 连接到 Oracle 数据库
            dsn = f"{host}:{port}/{service_name}"
            # 判断lib_dir是否存在
            if os.path.exists(lib_dir):
                oracledb.init_oracle_client(lib_dir=lib_dir)
            connection = oracledb.connect(user=user, password=password, dsn=dsn)
            cursor = connection.cursor()
            print("成功连接到ORACLE数据库")
            print(f"用户名: {user} 密码：{password} dsn：{dsn}")

        progress_bar = tqdm(total=0, desc="DML 执行进度", unit="条")
        # 执行 MYSQL DML 操作
        for sql in sql_list:
            cursor.execute(sql)  # 执行每一条 SQL 语句
            progress_bar.total += 1
            progress_bar.update(1)

        connection.commit()  # 提交更改

    except Exception as e:
        if progress_bar:
            progress_bar.close()
            progress_bar = None

        print(f"执行DML操作时出错： {e}")
    finally:
        # 确保在完成后关闭连接
        if progress_bar:
            progress_bar.close()
        if cursor:
            cursor.close()
        if connection:
            connection.close()


__all__ = ["config_analysis", "output_file", "print_file", "execute_dml"]


if __name__ == "__main__":
    print([resJson[1] for resJson in read_json(".")])
